package com.train.mgr.modules.biz.service.impl;

import cn.hutool.core.util.ObjectUtil;
import cn.hutool.json.JSON;
import cn.hutool.json.JSONUtil;
import com.alibaba.fastjson2.JSONObject;
import com.fasterxml.jackson.databind.JsonNode;
import com.fasterxml.jackson.databind.ObjectMapper;
import com.train.common.enums.AudioRuleEnum;
import com.train.mgr.modules.biz.dto.request.EmoRecognizeDTO;
import com.train.mgr.modules.biz.dto.response.*;
import com.train.mgr.modules.biz.entity.AudioMetricRule;
import com.train.mgr.modules.biz.entity.InterfaceLog;
import com.train.mgr.modules.biz.service.*;
import com.train.mgr.modules.biz.thirdparty.client.EmotionAnalyzeClient;
import com.train.mgr.modules.biz.thirdparty.client.FaceAnalyzeClient;
import com.train.mgr.modules.biz.utils.PromptTemplates;
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.stereotype.Service;

import java.io.File;
import java.math.BigDecimal;
import java.math.RoundingMode;
import java.net.URL;
import java.text.DecimalFormat;
import java.util.*;
import java.util.stream.Collectors;

/**
 * 自信度
 */
@Slf4j
@RequiredArgsConstructor
@Service("IConfidenceService")
public class ConfidenceServiceImpl implements IConfidenceService {

    @Autowired
    private FaceAnalyzeClient faceAnalyzeClient;

    @Autowired
    private EmotionAnalyzeClient emotionAnalyzeClient;

    @Autowired
    private IInterfaceLogService interfaceLogService;

    @Autowired
    private IFluencyService fluencyService;

    @Autowired
    private IAudioMetricRuleService audioMetricRuleService;

    @Autowired
    private IAliQwenService aliQwenService;

    @Value("${train.file.url}")
    private String fileVisitUrl;

    @Value("${file.upload-folder}")
    private String uploadFolder;

    private static final DecimalFormat THREE_SIG = new DecimalFormat("#.###");

    /* 5 个扣分情绪 */
    private static final Set<String> DEDUCT_EMOTIONS = new HashSet<>(
            Arrays.asList("忧虑", "沮丧", "恐惧", "焦虑", "担心"));

    /**
     * 自信度分数
     * @return
     */
    @Override
    public ScoreAndWenAnVo  calConfidenceScore(Long exerciseId,long audioDuration, AiAnalyzeResp aiAnalyzeResp,
                                         List<String> imagePathList, String audioFilePath,String audioText){
        long t = System.currentTimeMillis();
        ScoreAndWenAnVo bean = new ScoreAndWenAnVo();
        InterfaceLog interfaceLog = new InterfaceLog();
        long faceAnalyzeCost = 0;
      //  Integer longPauseCount = aiAnalyzeResp.getLong_pause_count();
        try{
            List<File> imagesFileList = imagePathList.stream()
                    .map(filePath -> new File(filePath))
                    .collect(Collectors.toList());

            List<File> imagesLogFileList = imagePathList.stream()
                    .map(filePath -> new File(fileVisitUrl +filePath))
                    .collect(Collectors.toList());
            interfaceLog.setRequestParam(JSONUtil.toJsonStr(imagesLogFileList));//视频人脸特征分析API--日志使用

            HeadVisualResp resp = faceAnalyzeClient.faceAnalyze(imagesFileList);//AI接口
            interfaceLog.setResposeResult(JSONUtil.toJsonStr(resp));//视频人脸特征分析API

            faceAnalyzeCost = System.currentTimeMillis() - t ;
            StringBuffer sb = new StringBuffer();
            BigDecimal v = BigDecimal.ZERO;
            BigDecimal eye =  BigDecimal.ZERO;
            BigDecimal head  =  BigDecimal.ZERO;
            BigDecimal faceExpressScore =  BigDecimal.ZERO;
            if(resp !=null && resp.getResult().size() >0 && !isResultEmpty(JSONUtil.toJsonStr(resp)) ){
                log.info("****************************exerciseId:{},resp.getResult().size():{}",exerciseId,resp.getResult().size());
                double[] faceRate = getFaceEyesHeadRate(resp.getResult());
                log.info("********exerciseId:{}, faceRate:{}",exerciseId,faceRate);
                double eyesRateScore = faceRate[0]; //眼神注视
                double headRateScore = faceRate[1]; //头部姿态
                log.info("眼神注视分:{}",eyesRateScore);
                log.info("头部姿态分:{}",headRateScore);
                //计算平均"面部表情"得分-
                faceExpressScore = this.getAvgExpressionScore(resp.getResult());
                log.info("面部表情得分:{}",faceExpressScore);

                eye   = BigDecimal.valueOf(eyesRateScore);
                head  = BigDecimal.valueOf(headRateScore);
                BigDecimal visual = eye.multiply(new BigDecimal("0.5"))
                        .add(faceExpressScore.multiply(new BigDecimal("0.3")))
                        .add(head.multiply(new BigDecimal("0.2")));
                //视觉分
                BigDecimal visualScore = visual.setScale(3, RoundingMode.HALF_UP);
                log.info("练习ID:{},视觉分:{}",exerciseId,visualScore);
                //对视觉分进行折算处理
                v = visualScore.multiply(new BigDecimal("0.4"));
            }else{
                log.error("视频人脸特征分析API异常，可能没有录制到头像.");
                log.info("视频人脸特征分析API异常，可能没有录制到头像");
            }

            AudioMetricRule eyeBean = audioMetricRuleService.findOneByMetricAndScore(AudioRuleEnum.eye_contact.getCode(),eye.doubleValue());
            AudioMetricRule faceExpBean = audioMetricRuleService.findOneByMetricAndScore(AudioRuleEnum.facial_expr.getCode(),faceExpressScore.doubleValue());
            AudioMetricRule headBean = audioMetricRuleService.findOneByMetricAndScore(AudioRuleEnum.head_pose.getCode(),head.doubleValue());
            if(ObjectUtil.isNotEmpty(eyeBean)){
                sb.append(eyeBean.getLevelName()+":"+eyeBean.getDescription()+"；");
            }
            if(ObjectUtil.isNotEmpty(faceExpBean)){
                sb.append(faceExpBean.getLevelName()+":"+faceExpBean.getDescription()+"；");
            }
            if(ObjectUtil.isNotEmpty(headBean)){
                sb.append(headBean.getLevelName()+":"+headBean.getDescription()+"；");
            }

            //心理压力分
            BigDecimal pressureScore = this.getPressureScore(exerciseId,audioFilePath,audioText);
            log.info("练习ID:{},心理压力分:{}",exerciseId,pressureScore);

            AudioMetricRule mentalBean = audioMetricRuleService.findOneByMetricAndScore(AudioRuleEnum.mental_stress.getCode(),pressureScore.doubleValue());
            if(ObjectUtil.isNotEmpty(mentalBean)){
                sb.append(mentalBean.getLevelName()+":"+mentalBean.getDescription()+"；");
            }
           // log.info("-------------sb:{}",sb.toString());
            String filterString = PromptTemplates.mergeByType(sb.toString());
            String prompt = String.format(PromptTemplates.CONFIDENCE_SUMMARY, filterString);
            log.info("【自信度】提示词:{}",prompt);
            String wenAn = aliQwenService.getQwenFeedBack(prompt);
            //log.info("--阿里通义返回自信度文案:{}",wenAn);
            //流畅度得分
            ScoreAndWenAnVo fluencyBean = fluencyService.calFluencyScore(audioDuration,aiAnalyzeResp);
            BigDecimal fluencyScore = fluencyBean.getScore();
            log.info("流畅度得分:{}",fluencyScore);
            BigDecimal f = fluencyScore.multiply(new BigDecimal("0.3"));
           // BigDecimal v = visualScore.multiply(new BigDecimal("0.4"));
            BigDecimal p = pressureScore.multiply(new BigDecimal("0.3"));

            BigDecimal confidenceScore = f.add(v).add(p).setScale(1, RoundingMode.HALF_UP);

            bean.setScore(confidenceScore);
            bean.setWenAn(wenAn);
            bean.setWpmAvgVoiced(aiAnalyzeResp.getWpm_avg_voiced());
            return bean;
        }catch (Exception ex){
            ex.printStackTrace();
            return new ScoreAndWenAnVo();
        }finally {
            interfaceLog.setExerciseId(exerciseId);
            interfaceLog.setRequestSpeedTime(faceAnalyzeCost+" 毫秒");
            interfaceLog.setInterfaceType("视频人脸特征分析API");
            interfaceLogService.save(interfaceLog);
        }
    }


    /**
     * 心理压力分
     * @param audioFilePath
     * @return
     */
    private BigDecimal getPressureScore(Long exerciseId,String audioFilePath,String text_asr){
        long t = System.currentTimeMillis();
        InterfaceLog interfaceLog = new InterfaceLog();
        try{
            String audio_url = fileVisitUrl + audioFilePath.replace(uploadFolder, "");;
            //log.info("心理压力计算分HTTP获取来自URL:{}",audio_url);
            String sample_rate = "16000";
            String top_k ="3";
            //log.info("======================text_asr:{}",text_asr);
            EmoRecognizeDTO reqBean = new EmoRecognizeDTO();
            reqBean.setAudio_url(audio_url);
            reqBean.setText_asr(text_asr);
            reqBean.setSample_rate(sample_rate);
            reqBean.setTop_k(top_k);
            interfaceLog.setRequestParam(JSONUtil.toJsonStr(reqBean));
            AiEmotionResp resp  = emotionAnalyzeClient.emoRecognize(reqBean);
            interfaceLog.setResposeResult(JSONUtil.toJsonStr(resp));//心理压力分API
            if(resp != null && resp.getScore()!=null && resp.getScore().size() >0){
                List<AiEmotionResp.EmotionItem> scoreList = resp.getScore();
                return this.getMentalPressure(scoreList);
            }else{
                log.info("心理压力分列表 为空～");
                return BigDecimal.valueOf(100).setScale(3, RoundingMode.HALF_UP);
            }
        }catch (Exception ex){
            ex.printStackTrace();
            return new BigDecimal(0);
        }finally {
            long emoRecognizeCost = System.currentTimeMillis() - t ;
            interfaceLog.setExerciseId(exerciseId);
            interfaceLog.setRequestSpeedTime(emoRecognizeCost+" 毫秒");
            interfaceLog.setInterfaceType("情绪识别接口API");
            interfaceLogService.save(interfaceLog);
        }
    }


    /**
     * 计算心理压力分
     * @param emotionList 情绪列表（来自 JSON 的 score 字段）
     * @return 心理压力分（100 - 压力扣分），保留 1 位小数
     */
    private BigDecimal getMentalPressure(List<AiEmotionResp.EmotionItem> emotionList) {
        if (emotionList == null || emotionList.isEmpty()) {
            return BigDecimal.valueOf(100).setScale(3, RoundingMode.HALF_UP);
        }

        /* 压力扣分 = 5 种扣分情绪的占比相加 */
        double deductTotal = emotionList.stream()
                .filter(e -> e.getEmotion() != null && DEDUCT_EMOTIONS.contains(e.getEmotion()))
                .mapToDouble(e -> Optional.ofNullable(e.getScore()).orElse(0.0))
                .sum()
                * 100;   // 转 100 分制
        log.info("压力扣分:{}",deductTotal);
        BigDecimal pressureScore = BigDecimal.valueOf(100)
                .subtract(BigDecimal.valueOf(deductTotal))
                .max(BigDecimal.ZERO);
        log.info("心理压力分:{}",pressureScore);
        return pressureScore.setScale(3, RoundingMode.HALF_UP);
    }



    /**
     * 计算平均面部表情得分
     * 规则：对每条“表情分布”取下标 0、1、3 相加后 *100，再对所有条数求平均
     * @param data 原始 JSON 列表
     * @return 平均面部表情得分，保留 1 位小数
     */
    private BigDecimal getAvgExpressionScore(List<HeadVisualItemVo> data) {
        if (data == null || data.isEmpty()) {
            return BigDecimal.ZERO;
        }
        BigDecimal total = BigDecimal.ZERO;
        for (HeadVisualItemVo item : data) {
            List<Double> dist = item.get表情分布();
            if (dist == null || dist.size() <= 3) {
                continue;
            }
            // 先截 3 位小数再累加
            BigDecimal score = BigDecimal.valueOf((dist.get(0) + dist.get(1) + dist.get(3)) * 100)
                    .setScale(6, RoundingMode.HALF_UP);
            total = total.add(score);
        }

        // 平均值再保留 3 位小数
        int size = data.size();
        return total.divide(BigDecimal.valueOf(size), 3, RoundingMode.HALF_UP);
    }

    /** 返回两个占比：0=眼神注视true占比，1=头部端正true占比 */
    private double[] getFaceEyesHeadRate(List<HeadVisualItemVo> list) {
        log.info("**************getFaceEyesHeadRate****************list:{}",list);
        if (list == null || list.isEmpty()) {
            return new double[]{0.0, 0.0};
        }
        long total = list.size();
        log.info("getFaceEyesHeadRate:total:{}",total);
        long eyeTrueNum  = list.stream()
                .filter(v -> Boolean.TRUE.equals(v.get眼神注视()))
                .count();
        long headTrueNum = list.stream()
                .filter(v -> Boolean.TRUE.equals(v.get头部端正()))
                .count();
        log.info("getFaceEyesHeadRate:eyeTrueNum{},headTrueNum:{}",eyeTrueNum,headTrueNum);

        BigDecimal bdTotal = BigDecimal.valueOf(total);
       // log.info("getFaceEyesHeadRate:bdTotal{}",bdTotal);
        // 先除得占比，再×100转百分制，保留3位小数
        double eyeRate  = BigDecimal.valueOf(eyeTrueNum)
                .divide(bdTotal, 5, RoundingMode.HALF_UP)
                .multiply(BigDecimal.valueOf(100))
                .setScale(3, RoundingMode.HALF_UP)
                .doubleValue();

        double headRate = BigDecimal.valueOf(headTrueNum)
                .divide(bdTotal, 5, RoundingMode.HALF_UP)
                .multiply(BigDecimal.valueOf(100))
                .setScale(3, RoundingMode.HALF_UP)
                .doubleValue();
        log.info("getFaceEyesHeadRate:eyeRate{},headRate:{}",eyeRate,headRate);
        return new double[]{eyeRate, headRate};
    }

    private boolean isResultEmpty(String json) {
        try {
            JsonNode root = new ObjectMapper().readTree(json);
            JsonNode result = root.get("result");
            // 1. 不存在或不是数组 → 空
            if (result == null || !result.isArray()) return true;
            // 2. 长度 0 → 空
            if (result.size() == 0) return true;
            // 3. 若还要判断“元素是否全是空对象”，可再遍历
            for (JsonNode obj : result) {
                if (obj.size() > 0) return false;   // 只要有 1 个非空对象 → 非空
            }
            return true;   // 全是 {} → 业务可视为空
        } catch (Exception e) {
            return true;   // 解析失败当空处理
        }
    }
}
